from typing import Any

from flask import current_app
from requests import HTTPError

from app.models.device_info import DeviceInfo
from app.models.metrics_data import NetworkStatus, MetricsData
from app.models.user_token import UserToken
from onething_client import DeviceOperations, DeviceManager, OnethingLogin


def get_authorization_info(auth_info: dict):
    return {
        'userid': auth_info.get('user_id'),
        'ak': auth_info.get('access_key'),
        'rk': auth_info.get('refresh_key')
    }


def create_device_operations(device_info):
    return DeviceOperations(device_info.number, device_info.url, **get_authorization_info(device_info.model_dump()))


def create_device_manager(user_token: UserToken) -> DeviceManager:
    return DeviceManager(**get_authorization_info(user_token.model_dump()))


def generate_url(user_token: UserToken, sn: str):
    generate_url_response = create_device_manager(user_token).generate_url(sn)
    if generate_url_response.get('iRet') == 0:
        data = generate_url_response.get('data', {})
        return data.get('url')
    else:
        raise RuntimeError('device url generate fail.', generate_url_response)


def login(**kwargs) -> Any | None:
    login_response = OnethingLogin().login(**kwargs)
    if login_response.get('errCode') == 0:
        data = login_response.get('data')
        data.update(kwargs)
        return UserToken.from_data(data)
    else:
        return None


def query_list(user_token: UserToken, device_number: str = None) -> [DeviceInfo]:
    query_list_response = create_device_manager(user_token).query_list(device_number)
    data = query_list_response.get('data', {})
    device_info_list = data.get('deviceInfoList', [])
    device_models = []
    for device_info in device_info_list:
        try:
            device_url = generate_url(user_token, device_info.get('sn'))
            if device_url is not None:
                device_info['url'] = device_url
                device_info.update(user_token.model_dump())
                device_model = DeviceInfo.from_data(device_info)
                device_models.append(device_model)
        except (HTTPError, Exception) as ex:
            current_app.logger.error(ex)
    return device_models


def fetch_onething_device_status(device_info: DeviceInfo):
    try:
        response = create_device_operations(device_info).fetch_pppoe_network_info()
        metrics_info_list = []
        if response.get('errcode') == 0:
            for multidial in response.get('multidial', []):
                network_status = NetworkStatus.from_data(multidial)
                multidial.update(device_info.model_dump())
                metrics_data = MetricsData.from_data(multidial)
                metrics_info_list.append((metrics_data.model_dump(), network_status))
        return metrics_info_list
    except HTTPError as he:
        raise he
